const ImageUtil = require('./image_util');

function processImage(bitmapData, gcodeParams) {
    // 计算灰度，提取为二维像素数据
    let width = bitmapData.width;
    let height = bitmapData.height
    let retData = new Array(width);
    let imageUtil = new ImageUtil();
    let gcp = gcodeParams;

    for (let i = 0; i < width; i++) {
        retData[i] = new Array(height);
        for (let j = 0; j < height; j++) {
            let idx = (j * width + i) << 2;
            let greyValue = 255;
            if (bitmapData.data[idx] == 255 && 
                bitmapData.data[idx + 1] == 180 && 
                bitmapData.data[idx + 2] == 20 && 
                bitmapData.data[idx + 3] == 255 && 
                (gcodeParams.markMode === 2 || gcodeParams.markMode === 3)) { // 圆柱模式遇到纯橙色点，是上位机的渲染颜色，读取为 黑色
                greyValue = 0; // 设置为纯黑
            } else{
                greyValue = 0.3333333 * (bitmapData.data[idx] + bitmapData.data[idx + 1] + bitmapData.data[idx + 2]);
                let A = bitmapData.data[idx + 3];
                // 取决于现在的上位机是否已经处理了透明度通道
                if (A !== 255)
                    greyValue = 255 - A + greyValue * A / 255;
                // if (bitmapData.data[idx+3] === 0) {countaaa++;}
                greyValue = Math.round(greyValue);
            }
            // let greyValue = 0.299*bitmapData.data[idx] + 0.587*bitmapData.data[idx+1] + 0.114*bitmapData.data[idx+2];
            retData[i][j] = greyValue;
        }
    }
    // 自动计算像素阈值
    // pixelThreshold = imageUtil.autoThreshold(retData, width, height);
    // if (gcodeParams.simulation) console.log('自动计算像素阈值：', pixelThreshold);
    // gamma 矫正
    // if (gcodeParams.gamma !== 1) {
    //     imageUtil.gammaCorrection(retData, width, height, gcodeParams.gamma);
    // }
    let haha = false;
    if (imageUtil.isBackgroundWhite(retData, width, height)) { // 白色背景图过滤掉浅白色
        gcodeParams.gray255Power = false;
        let bd = bitmapData;
        // imageUtil.deleteWhite(retData, width, height);
        imageUtil.adjustSourceImage(retData, width, height, bd.gamma, bd.brightness, bd.contrast);
    }else if(haha){
        imageUtil.gammaCorrection(retData, width, height, 0.45454545); 
        // 调整后的图片确实细节都保留了，但是在激光相纸上低功率的地方会打不穿，刚板之类的材料更严重
    }

    // imageUtil.gammaCorrection2(retData, width, height);
    if (gcodeParams.simulation) console.log('完成图像调整, 准备进行缩放和旋转');
    // TODO: 每个像素点变换到实际坐标系

    // let m = concatArray(gcodeParams.canvasMatrix, gcodeParams.matrix);
    let m = gcodeParams.matrix;

    let isScaled = false;
    if (Math.abs(m[1]) < 1e-4) { // theta 角度为 0 或 180
        if (m[0] < 0) { // theta 180
            retData = imageUtil.rotate90degrees(retData, width, height, 2);
        } else {// theta 0
            // 没有变化， 不做处理
        }
    } else if (Math.abs(m[0]) < 1e-4) { // theta 角度为 90 或 270
        if (m[1] < 0) { // theta 270
            retData = imageUtil.rotate90degrees(retData, width, height, 3);
        } else {// theta 90
            retData = imageUtil.rotate90degrees(retData, width, height, 1);
        }
        let tempWidth = gcodeParams.width;
        gcodeParams.width = gcodeParams.height;
        gcodeParams.height = tempWidth;
    } else {
        // 先缩放
        width = Math.floor(gcodeParams.width / gcodeParams.initBeamSize);
        height = Math.floor(gcodeParams.height / gcodeParams.initBeamSize);

        retData = imageUtil.scaleData(width, height, retData);
        // 后变换，上位机计算规则
        let sx = gcodeParams.width / bitmapData.width;
        let sy = gcodeParams.height / bitmapData.height;
        retData = imageUtil.transform(retData, gcodeParams.matrix, sx, sy);

        // TODO : 这里的变换和原始的坐标系映射有关，理论上这里应该乘以变换矩阵
        width = retData.length;
        height = retData[0].length;
        // gcodeParams.canvasMatrix[4] += (gcodeParams.width - width * gcodeParams.initBeamSize) / 2; // 图片中心点偏移量
        // gcodeParams.canvasMatrix[5] -= (gcodeParams.height - height * gcodeParams.initBeamSize) / 2; // 图片中心点偏移量
        // gcodeParams.xOffset += gcodeParams.matrix[4] - retData.length * gcodeParams.laserBeamSize /2; // 图片中心点
        // gcodeParams.yOffset += gcodeParams.matrix[5] - retData[0].length * gcodeParams.laserBeamSize/2; // 图片中心点
        // 计算实际坐标系中心点
        let newCenter = pointTransform(gcodeParams.canvasMatrix, [gcodeParams.matrix[4], gcodeParams.matrix[5]]);

        gcodeParams.xOffset = newCenter[0] - width * gcodeParams.initBeamSize / 2; // 起点偏移至左下角
        gcodeParams.yOffset = newCenter[1] - height * gcodeParams.initBeamSize / 2;

        // 扫描模式且插值
        if (gcp.interpTimes !== 1 && (gcp.bitmapMode === 0 || gcp.bitmapMode === 1)) {
            if (gcp.scanDir === 'X') {
                height *= gcp.interpTimes;
            } else {
                width *= gcp.interpTimes;
            }
            retData = imageUtil.scaleData(width, height, retData);
        }
        isScaled = true;
    }

    if (!isScaled) {
        // 计算实际坐标系中心点
        let newCenter = pointTransform(gcodeParams.canvasMatrix, [gcodeParams.matrix[4], gcodeParams.matrix[5]]);
        gcodeParams.xOffset = newCenter[0] - gcodeParams.width / 2; // 起点偏移至左下角
        gcodeParams.yOffset = newCenter[1] - gcodeParams.height / 2;
    }

    // TODO: 转换为 具体脉冲数 * 
    if (gcodeParams.markMode === 2) { // 旋转打标(抓盘)
        let d = gcodeParams.rotateParams.diameter; // 圆柱半径
        let p = 360 / gcp.rotateParams.perRevolutionPulsesClamp; // 脉冲数12800，一个脉冲 0.028125 度
        // 默认 scanDir 为 ‘X’
        let numPixelPulse = Math.round((gcodeParams.xOffset * 360  / (Math.PI * d) / p)); // 圆柱打标，弧长为 360°
        gcodeParams.aOffset = Math.ceil(numPixelPulse * p * 1000) / 1000;
    }else if (gcodeParams.markMode === 3){ // 旋转打标（滚轴）
        // let rd = gcp.rotateParams.rollerDiameter; // 滚轴直径
        // gcodeParams.aOffset = Math.ceil(gcodeParams.xOffset * 360 * 1000 / (Math.PI * rd)) / 1000;
        let rd = gcp.rotateParams.rollerDiameter * gcp.rotateParams.transmissionRatio; // 滚轴直径
        let p = 360 / gcp.rotateParams.perRevolutionPulsesRoller; // 脉冲数12800，一个脉冲 0.028125 度
        let unitArcLength = Math.PI * rd / gcp.rotateParams.perRevolutionPulsesRoller; // 一个脉冲对应的弧长
        let numPixelPulse = Math.round( gcodeParams.xOffset / unitArcLength);    
        gcodeParams.aOffset = Math.ceil(numPixelPulse * p * 1000) / 1000;
    }   
    // width = retData.length;
    // height = retData[0].length;

    // 插值算法
    if (gcodeParams.width !== 0 && gcodeParams.height !== 0 && !isScaled) {
        width = Math.floor(gcodeParams.xScaling * gcodeParams.width / gcodeParams.laserXBeamSize);
        height = Math.floor(gcodeParams.yScaling * gcodeParams.height / gcodeParams.laserYBeamSize);
        retData = imageUtil.scaleData(width, height, retData);
    }

    width = retData.length;
    height = retData[0].length;



    if (gcodeParams.simulation) console.log('完成缩放和旋转，准备进行黑白模式预处理');

    // 黑白模式预处理
    if (gcodeParams.bitmapMode === 1 || gcodeParams.bitmapMode === 3) {
        for (let i = 0; i < width; i++) {
            for (let j = 0; j < height; j++) {
                let alpha = retData[i][j];
                if (alpha < gcodeParams.pixelThreshold) {
                    retData[i][j] = 0;     // 黑色
                } else {
                    retData[i][j] = 255;   // 白色
                }
            }
        }
    }

    canvasMatrixProcess(gcodeParams, imageUtil, retData, width, height);

    if (gcodeParams.simulation) console.log('gamma 矫正完成，图片处理结束');

    if (gcodeParams.swapXY && gcodeParams.markMode !== 2 && gcodeParams.markMode !== 3) {
        let temp = gcodeParams.xOffset;
        gcodeParams.xOffset = gcodeParams.yOffset;
        gcodeParams.yOffset = temp;
        retData = imageUtil.transpose(retData, width, height, -1);
        width = retData.length;
        height = retData[0].length;
    }

    // 滚轴： 镜像输出
    if (gcp.markMode === 3 && gcp.rotateParams.mirrorImage){ 
        imageUtil.flip(retData, width, height, 1)
    }

    return {
        data: retData,
        width: width,
        height: height
    }
}

function pointTransform(a, p) {
    return new Array(
        a[0] * p[0] + a[2] * p[1] + a[4],
        a[1] * p[0] + a[3] * p[1] + a[5]
    )
}

function concatArray(a, b) {
    return new Array(
        a[0] * b[0] + a[2] * b[1],
        a[1] * b[0] + a[3] * b[1],
        a[0] * b[2] + a[2] * b[3],
        a[1] * b[2] + a[3] * b[3],
        a[0] * b[4] + a[2] * b[5],
        a[1] * b[4] + a[3] * b[5]
    )
}

function canvasMatrixProcess (gcodeParams, imageUtil, data, width, height) {
    // [1, 0, 0, -1, -50, 50]
    let m = gcodeParams.canvasMatrix;

    if (m[0] == 1 && m[1] == 0 && m[2] == 0 && m[3] == -1) { // reflect about x-aixs
        imageUtil.flip(data, width, height, 0);
        // flipX = true;
    } else if (m[0] == -1 && m[1] == 0 && m[2] == 0 && m[3] == 1) { // reflect about y-aixs
        imageUtil.flip(data, width, height, 1);
        // flipY = true;
    } else if (m[0] == -1 && m[1] == 0 && m[2] == 0 && m[3] == -1) { // reflect about origin
        imageUtil.flip(data, width, height, -1);
        // flipX = true;
        // flipY = true;
    } else if (m[0] == 0 && m[1] == 1 && m[2] == 1 && m[3] == 0) { // 

    }
}

module.exports = { processImage };